﻿using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.ComponentModel;
using System.Text;

namespace PasswdTool.SM4
{
    /// <summary>
    /// Sm4算法  
    /// 对标国际DES算法
    /// </summary>
    public class Sm4Crypt
    {
        public Sm4Crypt()
        {
            CryptoMode = Sm4CryptoEnum.ECB;
        }
        /// <summary>
        /// 秘钥
        /// </summary>
        public byte[] Key { get; set; }
        /// <summary>
        /// 向量
        /// </summary>
        public byte[] Iv { get; set; }
        /// <summary>
        /// 加密模式(默认ECB)
        /// </summary>
        public Sm4CryptoEnum CryptoMode { get; set; }

        #region 加密
        public CryptData Encrypt(byte []data)
        {
            CryptData result;
            switch (this.CryptoMode)
            {
                case Sm4CryptoEnum.ECB:
                    result = EncryptECB(data);
                    break;
                case Sm4CryptoEnum.CBC:
                    result = EncryptCBC(data);
                    break;
                default:
                    result = EncryptCBC(data);
                    break;
            }
            return result;
        }
        /// <summary>
        /// ECB加密
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public CryptData EncryptECB(byte[] data)
        {
            Sm4Context ctx = new Sm4Context
            {
                IsPadding = true
            };
            SM4 sm4 = new SM4();
            sm4.SetKeyEnc(ctx, this.Key);
            byte[] encrypted = sm4.Sm4CryptEcb(ctx, data);
            return new CryptData(encrypted);
        }
        /// <summary>
        /// CBC加密
        /// </summary>
        /// <returns></returns>
        public CryptData EncryptCBC(byte[] data)
        {
            Sm4Context ctx = new Sm4Context
            {
                IsPadding = true
            };
            SM4 sm4 = new SM4();
            sm4.SetKeyEnc(ctx, this.Key);
            byte[] encrypted = sm4.Sm4CryptCbc(ctx, this.Iv, data);
            return new CryptData(encrypted);
        }
        #endregion


        #region 解密
        public CryptData Decrypt(byte[] data)
        {
            CryptData result;
            switch (this.CryptoMode)
            {
                case Sm4CryptoEnum.ECB:
                    result = DecryptECB(data);
                    break;
                case Sm4CryptoEnum.CBC:
                    result = DecryptCBC(data);
                    break;
                default:
                    result = DecryptCBC(data);
                    break;
            }
            return result;
        }
        public CryptData DecryptECB(byte[] data)
        {
            Sm4Context ctx = new Sm4Context
            {
                IsPadding = true,
                Mode = 0
            };
            SM4 sm4 = new SM4();
            sm4.Sm4SetKeyDec(ctx, this.Key);
            byte[] decrypted = sm4.Sm4CryptEcb(ctx, data);
            return new CryptData(decrypted);
        }

        public CryptData DecryptCBC(byte[] data)
        {
            Sm4Context ctx = new Sm4Context
            {
                IsPadding = true,
                Mode = 0
            };
            SM4 sm4 = new SM4();
            sm4.Sm4SetKeyDec(ctx, this.Key);
            byte[] decrypted = sm4.Sm4CryptCbc(ctx, this.Iv,data);
            return new CryptData(decrypted);
        }
        #endregion

        /// <summary>
        /// 加密类型
        /// </summary>
        public enum Sm4CryptoEnum
        {
            /// <summary>
            /// ECB(电码本模式)
            /// </summary>
            [Description("ECB模式")]
            ECB = 0,
            /// <summary>
            /// CBC(密码分组链接模式)
            /// </summary>
            [Description("CBC模式")]
            CBC = 1
        }
    }
}
